//Pheonix Development Studios
//	The Next Dimension
//	Version 6.0
//RELEASE BUILD FUNCTIONING
// WITH SOUNDS
//WITH LEVEL EDITOR
//Fully Commented

#include "Game.h"
#include <ctime>
#include <vector>

float camX = 0;
float camY = 0;
float camZ = 10;
int frameCount = 0;


/* constructor */
Game::Game(void)
{
	/* green background */
	stateInfo.bgClearColor.red = 0;
	stateInfo.bgClearColor.green = 0;
	stateInfo.bgClearColor.blue = 0;

	/* init state */
	stateInfo.gameState = STATE_MAINMENU;
	renderingTimer = new Timer("RENDER");
	updateTimer = new Timer("UPDATE");
}

/* destructor */
Game::~Game(void)
{
	/* deallocate memory and clean up here. if needed */
}

/* 
 * initializeGame()
 * - this function is called in the constructor to initialize everything related
 *   to the game, i..e loading sprites etc.
 * - MUST be called prior to any drawing/updating (you should add in checks to ensure this occurs in the right order)
 */
void Game::initializeGame()
{
	velocity = new Vector(0.01,0.0,0.01);
	acceleration = new Vector(0,0,0);
	originPoint = new Vector(0,0,0);
	rotation = new Quaternion(36,false,true,false);
	//Spherical explosion around x-axis
	for(int i = 0; i < 10; i++)
	{
		
		this->radialexplosion.push_back(new Explosion(100,true,false,false,*velocity,*acceleration,*originPoint,0.4,0,0.3,1,5,5));
		velocity->multiplyVector(rotation);
	}
	//Spherical explosion around z-axis
	for(int i = 0; i < 10; i++)
	{
		
		this->radialexplosion.push_back(new Explosion(100,false,false,true,*velocity,*acceleration,*originPoint,0.4,0,0.3,1,5,10));
		velocity->multiplyVector(rotation);
	}
	//Ring like explosion, not spherical	
	this->radialexplosion.push_back(new Explosion(100,false,true,false,*velocity,*acceleration,*originPoint,0.4,0,0.3,1,5,15));
	
	
}

/* draw()
 * - this gets called automatically about 30 times per second
 * - this function just draws the sprites 
 */
void Game::draw()
{
	/* pre-draw - setup the rendering */
	PreDraw();

	/* draw - actually render to the screen */
	DrawGame();
	
	/* post-draw - after rendering, setup the next frame */
	PostDraw();
}

/*
 * Pre-Draw() is for setting up things that need to happen in order to draw
 *    the game, i.e. sorting, splitting things into appropriate lists etc.
 */
void Game::PreDraw()
{
	/* clear the screen */
	glViewport((GLint)0,(GLint)0,(GLint)stateInfo.windowWidth,(GLint)stateInfo.windowHeight);
	glClearColor((GLclampf)stateInfo.bgClearColor.red, 
				(GLclampf)stateInfo.bgClearColor.green, 
				 (GLclampf)stateInfo.bgClearColor.blue, 0);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glLoadIdentity(); // clear out the transformation matrix
	glEnable(GL_TEXTURE_2D); // turn on texturing
	glEnable(GL_DEPTH_TEST);

	// if we update our timer it will tell us the elapsed time since the previous 
	// frame that we rendered
	renderingTimer->tick();

	gluLookAt((GLdouble)camX,(GLdouble)camY,(GLdouble)camZ,/*Location of camera*/ 
		(GLdouble)0,(GLdouble)0,(GLdouble)0,/*where camera is looking*/ 
		(GLdouble)0,(GLdouble)1,(GLdouble)0);//last triplet determines up vector of camera
}

/* 
 * DrawGame()
 *  - this is the actual drawing of the current frame of the game.
 */
void Game::DrawGame()
{	
	/* here is where your drawing stuff goes */
	glColor3f((GLfloat)1,(GLfloat)0,(GLfloat)0);
	glLineWidth(10.f);
	glBegin(GL_LINES);
		glVertex3f(-200.0f, 0.0f, 0.0f); // x axis
		glVertex3f(200.0f, 0.0f, 0.0f); 
	glEnd();

	glColor3f((GLfloat)0,(GLfloat)0,(GLfloat)1);
	glLineWidth(10.f);
	glBegin(GL_LINES);
		glVertex3f(0.0f, -200.0f, 0.0f); // y axis
		glVertex3f(0.0f, 200.0f, 0.0f); 
	glEnd();
	
	glColor3f((GLfloat)1,(GLfloat)1,(GLfloat)1);
	glLineWidth(10.f);
	glBegin(GL_LINES);
		glVertex3f(0.0f, 0.0f, -200.0f); // z axis
		glVertex3f(0.0f, 0.0f, 200.0f); 
	glEnd();
	
	/*glEnable(GL_POINT_SMOOTH);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);*/
	for(int i = 0; i < radialexplosion.size(); i++)
	{
		radialexplosion[i]->draw();
	}
	glDisable(GL_BLEND);
	glDisable(GL_POINT_SMOOTH);

	//Drawing a fan of triangles specified around an origin(the first vertex call)
	/*glColor3f((GLfloat)1,(GLfloat)0,(GLfloat)0.5);
	glLineWidth(10.f);
	glBegin(GL_TRIANGLE_FAN);
		glVertex3f(20.f,20.f,20.f);
		glColor3f((GLfloat)0.5,(GLfloat)0,(GLfloat)0.35);
		glVertex3f(20.f,30.f,20.f);
		glColor3f((GLfloat)0.7,(GLfloat)0.,(GLfloat)0);
		glVertex3f(30.f,10.f,20.f);
		glColor3f((GLfloat)0.9,(GLfloat)0,(GLfloat)0);
		glVertex3f(30.f,30.f,30.f);
		glColor3f((GLfloat)0.1,(GLfloat)0,(GLfloat)0);
		glVertex3f(20.f,30.f,20.f);
	glEnd();*/
	//glColor3f((GLfloat)1,(GLfloat)0,(GLfloat)0.5);
	//glBegin(GL_POLYGON);
	//	glVertex3f(0.f,0.f,0.f);
	//	glColor3f((GLfloat)0.1,(GLfloat)0,(GLfloat)0);
	//	glVertex3f(10.f,0.f,0.f);
	//	glColor3f((GLfloat)0,(GLfloat)0.01,(GLfloat)0.35);
	//	glVertex3f(10.f,10.f,0);
	//	glColor3f((GLfloat)0.7,(GLfloat)0.,(GLfloat)0);
	//	glVertex3f(10.f,20.f,0);
	//	glColor3f((GLfloat)0.5,(GLfloat)0,(GLfloat)0.35);
	//	glVertex3f(0.f,20.f,0);
	//	glColor3f((GLfloat)0,(GLfloat)0.01,(GLfloat)0.35);
	//	glVertex3f(0.f,10.f,0);
	//	glColor3f((GLfloat)0,(GLfloat)0.01,(GLfloat)0.35);
	//	glVertex3f(0.f,10.f,5.0f);
	//glEnd();

	/*glColor3f(1,1,1);
	glutWireCube(5.f);*/

	/* this makes it actually show up on the screen */
	glutSwapBuffers();//also calls glFlush()

	
}

/*
 * PostDraw()
 *  - in here you should clean up and set up things for the next frame
 *  - i.e. once I've used my assets, I can change them to set up things for
 *    the next frame, usually just memory management or setting up game state 
 *    boolean values etc.  
 */
void Game::PostDraw()
{
	// nothing here at the moment
	for(int i = 0; i < radialexplosion.size(); i++)
	{
		if(radialexplosion[i]->dead == true)
		{
			radialexplosion.erase(radialexplosion.begin()+i);
			i--;
		}
	}
	
}

/* drawSprites()
 * - this function is what actually draws the sprites
 *   onto the screen at their appropriate location
 * - it actually loops through a list of active sprites
 *   and then sorts them by their layerID and then draws them
 * - the sorting has to happen so that you draw from back to front
 *   just like a painter and a canvas.
 */
void Game::drawSprites()
{
	/* we could just do the following to draw the three sprites
	   but that would be silly since we have a list of sprites to draw
	   stored, so all we need to do is go through the list and draw eaach 
	   sprite in the list */
	/* // silly way 
	testSprite->draw();
	animatedSprite->draw();
	animatedSprite2->draw();
	*/
	
	/* better way */
	/* this is better because it doesn't matter how many sprites we have, they will always be drawn */
	//std::vector<Sprite*>::iterator it; 
	//for(it=spriteListToDraw.begin(); it != spriteListToDraw.end();it++)
	//{
	//	Sprite *s = (*it);
	//	s->draw();
	//}

}


/*Reload()
This is used for when a player loses all their lives
It returns to the main menu and resets all inventory
It also redraws the tokens and the destructible boxes*/
void Game::Reload()
{
}

/*softReload()
This is used for when a player loses all their lives
It resets the player's position inventory except for lives
It also redraws the tokens and the destructible boxes*/
void Game::softReload()
{
	
}

/* update()
  - this function is essentially the game loop
    it gets called often and as such you
	don't actually need a "loop" to define the game
	it happens behind the scenes
  - think of this function as one iteration of the game loop
  - if you need to update physics calculations, sprite animation info,
    or sound etc, it goes in here
*/
void Game::update()
{	
	
	//sounds->updateSound();
	if(frameCount%900 == 0 && frameCount != 0)
	{
		for(int i = 0; i < 10; i++)
		{

			this->radialexplosion.push_back(new Explosion(100,true,false,false,*velocity,*acceleration,*originPoint,0.4,0,0.3,1,5,5));
			velocity->multiplyVector(rotation);
		}
		//Spherical explosion around z-axis
		for(int i = 0; i < 10; i++)
		{

			this->radialexplosion.push_back(new Explosion(100,false,false,true,*velocity,*acceleration,*originPoint,0.8,0,0.3,1,5,10));
			velocity->multiplyVector(rotation);
		}
		//Ring like explosion, not spherical	
		this->radialexplosion.push_back(new Explosion(100,false,true,false,*velocity,*acceleration,*originPoint,0.4,0,0.8,1,5,15));
	}
	frameCount++;

	
}

/* 
 * addSpriteToDrawList()
 * - this function simply pushes the sprite to the end of the list
 */
void Game::addSpriteToDrawList()
{
}

/*Removes the sprite from the draw list*/
void Game::removeSpriteFromDrawList()
{
}


/*************************************************/
/* INPUT - keyboard/mouse functions below        */
/*************************************************/
/* keyboardDown()
   - this gets called when you press a key down
   - you are given the key that was pressed
     and where the (x,y) location of the mouse is when pressed
*/
void Game::keyboardDown(unsigned char key, int mouseX, int mouseY)
{
	switch(key)
	{
	case 32: // the space bar
		break;
	case 96://tilde ~
		break;
	case 27: // the escape key
	case 'q': // the 'q' key
		exit(1);
		break;
	case 'a':
		camX-=0.5;
		break;
	case 'd':
		camX+=0.5;
		break;
	case 'w':
		camY+=0.5;
		break;
	case 's':
		camY-=0.5;
		break;
	case 'r':
		camZ+=0.5;
		break;
	case 'f':
		camZ-=0.5;
		break;
		
	}
}
/* keyboardUp()
   - this gets called when you lift a key up
   - you are given the key that was pressed
     and where the (x,y) location of the mouse is when pressed
*/
void Game::keyboardUp(unsigned char key, int mouseX, int mouseY)
{
	switch(key)
	{
	case 32: // the space bar
		break;
	case 27: // the escape key
		break;
	case 'q': // the 'q' key
		exit(1);
		break;
	}
}

/*
 * mouseClicked
 * - this function is called when the mouse is clicked and it handles the 
 *   input state managment
 */
void Game::mouseClicked(int button, int state, int x, int y)
{
	if(state == GLUT_DOWN) 
	{
		input.mouseDown = true;
		input.clickX = x*stateInfo.ratioWidth-(stateInfo.windowWidth/2);
		input.clickY = (stateInfo.windowHeight-y)*stateInfo.ratioHeight;
		input.button = button;
		
		switch(button)
		{
		case GLUT_LEFT_BUTTON:
			break;
		case GLUT_RIGHT_BUTTON:
			break;
		case GLUT_MIDDLE_BUTTON:
			break;
		}
	}
	else
	{
		input.mouseDown = false;
	}

}

/*
 * mouseMoved(x,y)
 * - this occurs only when the mouse is pressed down
 *   and the mouse has moved.  you are given the x,y locations
 *   in window coordinates (from the top left corner) and thus 
 *   must be converted to screen coordinates using the screen to window pixels ratio
 *   and the y must be flipped to make the bottom left corner the origin.
 */
void Game::mouseMoved(int x, int y)
{
	/* convert from window to screen pixel coordinates */
	input.currentX = x*stateInfo.ratioWidth-(stateInfo.windowWidth/2);
	input.currentY = (stateInfo.windowHeight-y)*stateInfo.ratioHeight;

	float placex = input.clickX;
	float placey = input.clickY;
	
	if(input.mouseDown)
	{
		if(input.button == GLUT_LEFT_BUTTON)
		{
			
		}
	}
}

void Game::mouseHover(int x, int y)
{
	/* convert from window to screen pixel coordinates */
	input.currentX = x*stateInfo.ratioWidth-(stateInfo.windowWidth/2);
	input.currentY = (stateInfo.windowHeight-y)*stateInfo.ratioHeight;

}
